from google.appengine.api import memcache
from google.appengine.ext import db
from google.appengine.ext.db import stats
from lg_config import HMAC_KEY
from lg_flight_db import get_departure_flight_info_db, get_airport_info_db, \
    AirlineInfo, AirportInfo
from lg_flight_stats_api import get_departure_flight_info_api, \
    get_airport_info_api, get_airline_info_api
from lg_security_util import make_secure_val, check_secure_val, make_pw_hash, \
    valid_pw_hash
from lg_string_util import valid_username, valid_password, valid_email
import jinja2
import json
import os
import webapp2

template_dir = os.path.join(os.path.dirname(__file__), 'templates')
jinja_env = jinja2.Environment(loader=jinja2.FileSystemLoader(template_dir),
                               autoescape=True)
def users_key(group='default'):
    return db.Key.from_path('users', group)

class LazyGalaxyHandler(webapp2.RequestHandler):
    def write(self, *a, **kw):
        self.response.out.write(*a, **kw)

    def render_str(self, template, **params):
        params['user'] = self.user
        t = jinja_env.get_template(template)
        return t.render(params)

    def render(self, template, **kw):
        self.write(self.render_str(template, **kw))

    def render_json(self, collection):
        json_txt = json.dumps(collection)
        self.response.headers['Content-Type'] = 'application/json; charset=UTF-8'
        self.write(json_txt)

    def set_secure_cookie(self, name, val):
        cookie_val = make_secure_val(val, HMAC_KEY)
        self.response.headers.add_header(
            'Set-Cookie',
            '%s=%s; Path=/' % (name, cookie_val))

    def read_secure_cookie(self, name):
        cookie_val = self.request.cookies.get(name)
        return cookie_val and check_secure_val(cookie_val)

    def login(self, user):
        self.set_secure_cookie('user_id', str(user.key().id()))

    def logout(self):
        self.response.headers.add_header('Set-Cookie', 'user_id=; Path=/')

    def initialize(self, *a, **kw):
        webapp2.RequestHandler.initialize(self, *a, **kw)
        uid = self.read_secure_cookie('user_id')
        self.user = uid and UserInfo.by_id(int(uid))

        if self.request.url.endswith('.json'):
            self.format = 'json'
        else:
            self.format = 'html'

class UserInfo(db.Model):
    name = db.StringProperty(required=True)
    pw_hash = db.StringProperty(required=True)
    email = db.EmailProperty(required=True)

    @classmethod
    def by_id(cls, uid):
        return UserInfo.get_by_id(uid, parent=users_key())

    @classmethod
    def by_name(cls, name):
        u = UserInfo.all().filter('name =', name).get()
        return u

    @classmethod
    def register(cls, name, password, email=None):
        pw_hash = make_pw_hash(name, password)
        return UserInfo(parent=users_key(),
                    name=name,
                    pw_hash=pw_hash,
                    email=email)

    @classmethod
    def login(cls, name, password):
        u = cls.by_name(name)
        if u and valid_pw_hash(name, password, u.pw_hash):
            return u
        
class Main(LazyGalaxyHandler):
    def get(self):
        self.render('main.html')
        
class Signup(LazyGalaxyHandler):
    def get(self):
        self.render("signup.html")

    def post(self):
        have_error = False
        self.username = self.request.get('username')
        self.password = self.request.get('password')
        self.verify = self.request.get('verify')
        self.email = self.request.get('email')

        params = dict(username=self.username,
                      email=self.email)

        if not valid_username(self.username):
            params['error_username'] = "That's not a valid username."
            have_error = True

        if not valid_password(self.password):
            params['error_password'] = "That wasn't a valid password."
            have_error = True
        elif self.password != self.verify:
            params['error_verify'] = "Your passwords didn't match."
            have_error = True

        if not valid_email(self.email):
            params['error_email'] = "That's not a valid email."
            have_error = True

        if have_error:
            self.render('signup.html', **params)
        else:
            #make sure the user doesn't already exist
            u = UserInfo.by_name(self.username)
            if u:
                msg = 'That user already exists.'
                self.render('signup.html', error_username=msg)
            else:
                u = UserInfo.register(self.username, self.password, self.email)
                u.put()
                self.login(u)
                self.redirect('/')

class Login(LazyGalaxyHandler):
    def get(self):
        self.render('login.html')

    def post(self):
        username = self.request.get('username')
        password = self.request.get('password')

        u = UserInfo.login(username, password)
        if u:
            self.login(u)
            self.redirect('/')
        else:
            msg = 'Invalid login'
            self.render('login.html', error=msg)

class Logout(LazyGalaxyHandler):
    def get(self):
        self.logout()
        self.redirect('/')
        
class Travel(LazyGalaxyHandler):
    def get(self):
        memcache_key = "airport_dict";
        airport_dict = memcache.get(memcache_key); #@UndefinedVariable
        if airport_dict is None:
            airport_dict = get_airport_info_db('CH');
            memcache.set(memcache_key, airport_dict) #@UndefinedVariable
        
        self.render('travel.html', airport_dict=airport_dict.values())
        
    def post(self):
        departure_airport_iata_code = self.request.get("departure_airport_name").split()[0]
        departure_date = self.request.get("departure_date")
        
        memcache_key = "departures_" + departure_date + '_' + departure_airport_iata_code
        departures = memcache.get(memcache_key) #@UndefinedVariable
        if departures is None:
            departures = get_departure_flight_info_db(departure_airport_iata_code, departure_date)
            if not departures:
                departures = get_departure_flight_info_api(departure_airport_iata_code, departure_date)
            memcache.set(memcache_key, departures) #@UndefinedVariable
        
        self.render('travel_post.html', departures=departures)

class Admin(LazyGalaxyHandler):
    def get(self):
        self.render('admin.html')
    
    def post(self):
        command = self.request.get("command")
        info = ""
        error = ""

        if command == 'flush memcache':
            memcache.flush_all() #@UndefinedVariable 
            info = "memcache: " + str(memcache.get_stats()) #@UndefinedVariable
        elif command == 'get memcache stats':
            info = "memcache: " + str(memcache.get_stats()) #@UndefinedVariable
        elif command == 'get db stats':
            info = "db stats: " + str(stats.GlobalStat.all().get())
        elif command == 'populate airports db':
            #db.delete("AirportInfo")
            airport_info_dict = get_airport_info_api();
            airport_info_list = airport_info_dict.values()
            for airport_info in airport_info_list:
                AirportInfo.populate(airport_info).put()
            info = "added: " + str(len(airport_info_list))
        elif command == 'populate airlines db':
            #db.delete("AirportInfo")
            airline_info_dict = get_airline_info_api()
            airline_info_list = airline_info_dict.values()
            for airline_info in airline_info_list:
                AirlineInfo.populate(airline_info).put()
            info = "added: " + str(len(airline_info_list))
        else:
            error = "command not found"
   
        self.render('admin.html', info=info, error=error)

app = webapp2.WSGIApplication([('/', Main),
                               ('/signup', Signup),
                               ('/login', Login),
                               ('/logout', Logout),
                               ('/travel', Travel),
                               ('/admin', Admin),
                               ],
                              debug=True)
